﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using KEW.InterFace;

namespace AutoGam
{
    public class UsbLaiKa : ICard
    {
        [DllImport("umf.DLL", EntryPoint = "fw_init")]
        public static extern Int32 fw_init(Int16 port, Int32 baud);
        [DllImport("umf.DLL", EntryPoint = "fw_config_card")]
        public static extern Int32 fw_config_card(Int32 icdev, Byte flags);
        [DllImport("umf.DLL", EntryPoint = "fw_exit")]
        public static extern Int32 fw_exit(Int32 icdev);
        [DllImport("umf.Dll", EntryPoint = "fw_request")]
        public static extern Int32 fw_request(Int32 icdev, Byte _Mode, ref UInt32 TagType);
        [DllImport("umf.DLL", EntryPoint = "fw_anticoll")]
        public static extern Int32 fw_anticoll(Int32 icdev, Byte _Bcnt, ref ulong _Snr);
        [DllImport("umf.DLL", EntryPoint = "fw_select")]
        public static extern Int32 fw_select(Int32 icdev, UInt32 _Snr, ref Byte _Size);
        [DllImport("umf.DLL",EntryPoint="fw_card")]
        public static extern Int32 fw_card(Int32 icdev,Byte _Mode,ref ulong _Snr);
        [DllImport("umf.DLL",EntryPoint="fw_load_key")]
        public static extern Int32 fw_load_key(Int32 icdev,Byte _Mode,Byte _SecNr,ref Byte _NKey);
        [DllImport("umf.DLL",EntryPoint="fw_authentication")]
        public static extern Int32  fw_authentication(Int32 icdev,Byte _Mode,Byte _SecNr);
        [DllImport("umf.DLL",EntryPoint="fw_read")]
        public static extern  Int32  fw_read(Int32 icdev,Byte _Adr,ref Byte _Data);

        [DllImport("umf.dll",EntryPoint="fw_read_hex")]
        public static extern Int16 fw_read_hex(Int32 icdev, Byte _Adr, StringBuilder _Data);

        [DllImport("umf.DLL", EntryPoint = "fw_write")]
        public static extern  Int32  fw_write(Int32 icdev,Byte _Adr,ref Byte _Data);

        [DllImport("umf.dll", EntryPoint = "fw_write_hex")]
        public static extern Int16 fw_write_hex(Int32 icdev, Byte _Adr, string _Data);

        [DllImport("umf.DLL", EntryPoint = "fw_halt")]
        public static extern  Int32  fw_halt(Int32 icdev);
        [DllImport("umf.DLL", EntryPoint = "fw_changeb3")]
        public static extern Int32  fw_changeb3(Int32 icdev,Byte _SecNr,ref Byte _KeyA,ref Byte _CtrlW,Byte _Bk,
				ref Byte _KeyB);
        [DllImport("umf.DLL", EntryPoint = "fw_initval")]
        public static extern Int32 fw_initval(Int32 icdev,Byte _Adr,UInt32 _Value);
        [DllImport("umf.DLL", EntryPoint = "fw_increment")]
        public static extern Int32 fw_increment(Int32 icdev,Byte _Adr,UInt32 _Value);
        [DllImport("umf.DLL", EntryPoint = "fw_readval")]
        public  static extern Int32 fw_readval(Int32 icdev,Byte _Adr,ref UInt32 _Value);
        [DllImport("umf.DLL", EntryPoint = "fw_decrement")]
        public static extern Int32  fw_decrement(Int32 icdev,Byte _Adr,UInt32 _Value);
        [DllImport("umf.DLL", EntryPoint = "fw_restore")]
        public static extern Int32  fw_restore(Int32  icdev,Byte _Adr);
        [DllImport("umf.DLL", EntryPoint = "fw_transfer")]
        public static extern Int32  fw_transfer(Int32 icdev,Byte _Adr);
        [DllImport("umf.DLL", EntryPoint = "fw_beep")]
        public static extern Int32  fw_beep(Int32 icdev,UInt32 _Msec);
        [DllImport("umf.DLL", EntryPoint = "fw_getver")]
        public static extern  Int32 fw_getver(Int32 icdev,ref Byte buff);
        [DllImport("umf.DLL", EntryPoint = "fw_reset")]
        public static extern Int16  fw_reset(Int32 icdev,UInt16 _Msec);
        [DllImport("umf.DLL",EntryPoint="hex_a")]
        public static extern void hex_a(ref Byte hex, ref Byte a,Int16 len);

        //Ultralight卡函数
        [DllImport("umf.dll",EntryPoint="fw_request_ultralt")]
        public static extern Int32 fw_request_ultralt(Int32 icdev, Byte _Mode);
        [DllImport("umf.dll",EntryPoint="fw_anticall_ultralt")]
        public static extern Int32 fw_anticall_ultralt(Int32 icdev, ref ulong _Snr);
        [DllImport("umf.dll", EntryPoint = "fw_select_ultralt")]
        public static extern Int32 fw_select_ultralt(Int32 icdev, ulong _Snr);
        [DllImport("umf.dll", EntryPoint = "fw_write_ultralt")]
        public static extern Int32 fw_write_ultralt(Int32 icdev, Byte iPage, ref Byte wdata);
        [DllImport("umf.dll", EntryPoint = "fw_read_ultralt")]
        public static extern Int32 fw_read_ultralt(Int32 icdev, Byte iPage, ref Byte rdata);


        Int32 ihdev;
        Int32[] devs;//保存多个设备句柄的数组
        Int32 state;
        bool isAuthen;
        bool isComOpen;
        Int32 curCardtype;

        Byte sector=6;//4;//M1 S70 卡操作的扇区号
        Byte Address = 24;//16;//第16块，注意：测试的时候不要写密码块
        //每个扇区的最后一个块是密码块，比如地址号为3、7、11等是密码块

        private Boolean _enable;
        private String _flag;

        public Boolean Enable { get { return _enable; } }
        public String Flag { get { return _flag; } }

        public UsbLaiKa()
        {
            Int32 tmphdev = 0;
            int i = 0;
            ihdev = fw_init(100, 0);


            if (ihdev > 0)
            {
                Byte[] key = new Byte[6];
                key[0] = 0xff;
                key[1] = 0xff;
                key[2] = 0xff;
                key[3] = 0xff;
                key[4] = 0xff;
                key[5] = 0xff;
                state = fw_load_key(ihdev, 0, sector, ref key[0]);

                if (state == 0)
                {
                    _enable = true;
                    Beep();
                }
                else
                {
                    _enable = false;
                }
            }
            else
            {
                _enable = false;
            }
        }

        public String GetSerial()
        {
            ulong cardnumber = new ulong();//卡号请定义成无符号的ulong型变量
            state = fw_card(ihdev, 0x31, ref cardnumber);
            if (state == 0)
            {
                String cardSerial = "";
                byte[] a = System.BitConverter.GetBytes(cardnumber);
                for (int i = 0; i < 4; i++)
                {
                    cardSerial += a[i].ToString("X2");
                }

                return cardSerial;
            }
            else
            {
                _flag = "GetSerial rf_card 错误" + state;
                return String.Empty;
            }
        }

        /// <summary>
        /// 读块区
        /// </summary>
        /// <param name="block">块区号</param>
        /// <returns>返回值</returns>
        public String ReadBlock(Block block)
        {
            if (!Enable) return "";
            byte[] output = new byte[32];
            ulong cardnumber = new ulong();
            state = fw_card(ihdev, 0x31, ref cardnumber);
            state = fw_authentication(ihdev, 0, (byte)((int)block / 4));
            if (state == 0)
            {
                state = fw_read(ihdev, (byte)block, ref output[0]);
                if (state == 0)
                {
                    return Encoding.GetEncoding("GBK").GetString(output).Split('\0')[0];
                }
                else
                {
                    _flag = "ReadBlock rf_read 错误" + state;
                    return String.Empty;
                }
            }
            else
            {
                _flag = "ReadBlock rf_authentication 错误" + state;
                return String.Empty;
            }
        }

        /// <summary>
        /// 向某一块区中写数据 可写入8个长度的字符
        /// </summary>
        /// <param name="value">信息</param>
        /// <param name="block">块区</param>
        /// <returns>执行结果返回值</returns>
        public Boolean WriteBlock(String value, Block block)
        {
            if (!Enable) return false;
            byte[] snr = new byte[5];
            ulong cardnumber = new ulong();
            state = fw_card(ihdev, 0x31, ref cardnumber);
            state = fw_authentication(ihdev, 0, (byte)((int)block / 4));

            if (state == 0)
            {
                String cut = Left(value, 16);
                byte[] input = Encoding.GetEncoding("GBK").GetBytes(cut);
                byte[] input2 = new Byte[16];
                for (int i = 0; i < input2.Length; i++)
                {
                    if (i < input.Length)
                    {
                        input2[i] = input[i];
                    }
                    else
                    {
                        input2[i] = 0x00;
                    }
                }
                state = fw_write(ihdev, (byte)block, ref input2[0]);
                if (state == 0)
                {
                    String reload = ReadBlock(block);
                    if (reload == cut)
                    {

                        return true;
                    }
                    else
                    {
                        _flag = "rf_write ReadBlock 校验错误" + state + ",块区:" + (int)block + "reload:[" + reload + "],原始[" + value + "]";
                        return false;
                    }
                }
                else
                {
                    _flag = "rf_write 错误" + state + ",块区:" + (int)block;
                    return false;
                }
            }
            else
            {
                _flag = "rf_authentication 错误" + state + ",块区:" + (int)block;
                return false;
            }
        }

        public void Beep()
        {
            if (!Enable) return;
            fw_beep(ihdev, 10);
        }

        /// <summary>
        /// 退出
        /// </summary>
        public void Exit()
        {
            if (ihdev > 0)
            {
                fw_exit(ihdev);
                ihdev = -1;
            }
        }

        private String Left(String data, int len)
        {
            int curLen = 0;
            int curIdx = 0;
            String retStr = "";
            while (curIdx <= data.Length - 1)
            {
                Byte[] curCharBytes = Encoding.GetEncoding("GBK").GetBytes(data[curIdx].ToString());
                if (curLen + curCharBytes.Length <= len)
                {
                    curLen += curCharBytes.Length;
                    retStr += data[curIdx].ToString();
                    curIdx++;
                }
                else
                {
                    break;
                }

            }

            return retStr;
        }

    }


}
